package com.qs.es.service;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qs.constant.EsConstant;
import com.qs.mapper.CollectGoodsMapper;
import com.qs.mapper.CommentMapper;
import com.qs.mapper.GoodsMapper;
import com.qs.model.dto.GoodsIndexDto;
import com.qs.model.entity.CollectGoods;
import com.qs.model.entity.Comment;
import com.qs.model.entity.Goods;
import com.qs.model.es.EsGoodsDto;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 封装ES的一些常用方法
 * @Author: @weixueshi
 * @Create: 2023/12/29 - 10:11
 * @Version: v1.0
 */
@Service
@RequiredArgsConstructor
public class EsGoodsService {

    private final RestHighLevelClient client;

    private final CollectGoodsMapper collectGoodsMapper;

    private final CommentMapper commentMapper;

    private final GoodsMapper goodsMapper;

    /**
     * 批量导入商品数据
     * @param list
     */
    public void bulkSaveGoods(List<EsGoodsDto> list) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        list.stream().forEach(goods -> {
            bulkRequest.add(new IndexRequest(EsConstant.INDEX_NAME_GOODS)
                    .id(goods.getKey().toString())
                    .source(JSON.toJSONString(goods),XContentType.JSON));
        });
        client.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * 封装数据
     * @param response
     * @return
     */
    private List<EsGoodsDto> handlerResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<EsGoodsDto> list = new ArrayList<EsGoodsDto>();
        for(SearchHit hit : hits){
            String json = hit.getSourceAsString();
            EsGoodsDto esGoodsDto = JSON.parseObject(json, EsGoodsDto.class);
            list.add(esGoodsDto);
        }
        return list;
    }

    /**
     * 返回搜索匹配到的商品id
     * @param param
     * @return
     * @throws IOException
     */
    public List<Integer> frontSearchList(String param) throws IOException {
        SearchRequest request = new SearchRequest(EsConstant.INDEX_NAME_GOODS);
        if(StringUtils.isBlank(param)){
            return null;
        }else{
            //按商品名称搜索
            request.source().query(QueryBuilders.multiMatchQuery(param,"name"));
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //处理返回数据
            List<EsGoodsDto> list = handlerResponse(response);
            List<Integer> goodsIds = list.stream().map(EsGoodsDto::getKey).collect(Collectors.toList());
            return goodsIds;
        }
    }

    /**
     * 商品搜索
     * @param ids
     * @return
     */
    public List<GoodsIndexDto> searchGoodsFrontList(List<Integer> ids,String name) throws IOException {
        if(!CollectionUtils.isEmpty(ids)){
            SearchRequest request = new SearchRequest(EsConstant.INDEX_NAME_GOODS);
            //根据key查询
            request.source().query(QueryBuilders.termsQuery("key",ids));
            request.source().query(QueryBuilders.multiMatchQuery(name,"name"));
            //高亮查询完成
            request.source().highlighter(new HighlightBuilder()
                    .field("name")
                    .preTags("<font color='red'>")
                    .postTags("</font>")
                    .requireFieldMatch(false));
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //高亮处理返回数据
            List<EsGoodsDto> list = handlerGoodsLightResponse(response);
            //以上已经完成高亮数据处理
            //封装数据
            if(!CollectionUtils.isEmpty(list)){
                return this.handleGoodsData(list);
            }
        }
        return null;
    }

    private List<GoodsIndexDto> handleGoodsData(List<EsGoodsDto> list) {
        List<GoodsIndexDto> result = new ArrayList<GoodsIndexDto>();
        list.stream().forEach(goods -> {
            //获取每个商品的收藏量
            Long collectNum = collectGoodsMapper.selectCount(new QueryWrapper<CollectGoods>()
                    .eq("goods_id", goods.getKey()));
            //获取每个商品的评论量
            Long commentNum = commentMapper.selectCount(new QueryWrapper<Comment>()
                    .eq("goods_id", goods.getKey()));

            Goods selectById = goodsMapper.selectById(goods.getKey());

            GoodsIndexDto dto = new GoodsIndexDto();
            dto.setId(goods.getKey());
            dto.setGoodsName(goods.getName());
            dto.setImage(goods.getImage());
            dto.setPrice(goods.getPrice());
            dto.setBrowse(selectById.getBrowse());
            dto.setSale(Long.valueOf(goods.getSale()));
            dto.setCollectNum(collectNum);
            dto.setCommentNum(commentNum);
            result.add(dto);
        });
        return result;
    }

    private List<EsGoodsDto> handlerGoodsLightResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<EsGoodsDto> list = new ArrayList<EsGoodsDto>();
        for(SearchHit hit : hits){
            String json = hit.getSourceAsString();
            EsGoodsDto esGoodsDto = JSON.parseObject(json, EsGoodsDto.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(!CollectionUtils.isEmpty(highlightFields)){
                HighlightField highlightField = highlightFields.get("name");
                if(highlightField != null){
                    String name = highlightField.getFragments()[0].string();
                    esGoodsDto.setName(name);
                }
            }
            list.add(esGoodsDto);
        }
        return list;
    }

    /**
     * 新增商品文档
     * @param esGoodsDto
     * @throws IOException
     */
    public void addDocument(EsGoodsDto esGoodsDto) throws IOException {
        IndexRequest indexRequest = new IndexRequest(EsConstant.INDEX_NAME_GOODS).id(esGoodsDto.getKey().toString());
        indexRequest.source(JSON.toJSONString(esGoodsDto),XContentType.JSON);
        client.index(indexRequest,RequestOptions.DEFAULT);
    }

    /**
     * 删除文档
     * @param list
     * @throws IOException
     */
    public void deleteDocument(List<Integer> list,String indexName) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        list.stream().forEach(id -> {
            bulkRequest.add(new DeleteRequest(indexName,id.toString()));
        });
        client.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * 删除索引库
     * @throws IOException
     */
    public void deleteIndex(String indexName) throws IOException {
        DeleteIndexRequest deleteRequest = new DeleteIndexRequest(indexName);
        client.indices().delete(deleteRequest,RequestOptions.DEFAULT);
    }

    /**
     * 判断索引库是否存在
     * @return
     * @throws IOException
     */
    public boolean isExits(String indexName) throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        return client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }
}
